home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmiSoft / Util / Cli / Howdif.lha / howdif / source / howdif.c next >
C/C++ Source or Header  |  2003-01-30  |  11KB  |  359 lines

  1. /* HowDif 2.02a for Amiga
  2.  
  3.    Quick-and-dirty routine written to compare two files. The assumption is
  4.    that they are files known to be different from one another, already. I
  5.    want to know HOW different they are from one another. Essentially, this
  6.    program reads two files, notes the number of bytes read, and notes
  7.    how many bytes do not match. (This is a strict byte-for-byte
  8.    comparison.)
  9.  
  10.    Written by James Jacobs and Ward Shrake
  11.    Last update: January 31, 2003 */
  12.  
  13. #include <exec/types.h>
  14. #include <dos/dos.h>
  15.  
  16. #include <stdlib.h>          /* EXIT_SUCCESS, EXIT_FAILURE */
  17.  
  18. typedef signed char  FLAG;   /* 8-bit signed quantity (replaces BOOL) */
  19. typedef signed char  SBYTE;  /* 8-bit signed quantity (replaces Amiga BYTE) */
  20. typedef signed short SWORD;  /* 16-bit signed quantity (replaces Amiga WORD) */
  21. typedef signed long  SLONG;  /* 32-bit signed quantity (same as LONG) */
  22. #define elif         else if
  23. #define AGLOBAL      ;       /* global (project-scope) */
  24. #define MODULE       static  /* external static (file-scope) */
  25. #define PERSIST      static  /* internal static (function-scope) */
  26. #define AUTO         auto    /* automatic (function-scope) */
  27.  
  28. MODULE STRPTR                MemoryPtr[3]  = {NULL, NULL};
  29. MODULE struct FileInfoBlock* FIBPtr        = NULL;
  30. MODULE struct RDArgs*        ArgsPtr       = NULL;
  31. MODULE BPTR                  FileHandle    = NULL;
  32. MODULE TEXT                  output[1024 + 1],
  33.                              ansi1[20],
  34.                              ansi2[20];
  35. MODULE FLAG                  inverted      = FALSE,
  36.                              vanilla       = FALSE;
  37. MODULE ULONG                 size[3];
  38.  
  39. MODULE void cleanexit(SLONG rc);
  40. MODULE void hexalize(UBYTE data);
  41. MODULE void invert(void);
  42. MODULE void deinvert(void);
  43.  
  44. int main(int argc, char** argv)
  45. {   AUTO    ULONG  i, j,
  46.                    length,
  47.                    percent1, percent2,
  48.                    signals,
  49.                    br,
  50.                    bw = 0,   // number of total mismatches found
  51.                    bpl = 14; // bytes per line
  52.     AUTO    FLAG   compare = FALSE;
  53.     PERSIST TEXT   arcadia[] = " /\\abcdefghijklm0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,+$nopqrstu";
  54.     AUTO    STRPTR primary, secondary;
  55.     AUTO    SLONG  args[5] = {0L, 0L, 0L, 0L, 0L};
  56.  
  57.     if (0)
  58.     {   strcpy(arcadia, "$VER: HowDif 2.02a for Amiga (31.1.2003)");
  59.     }
  60.  
  61.     ansi1[0] = 0x9b;
  62.     ansi1[1] = 0;
  63.     strcat(ansi1, "0;32;40;>0m"); // means `go white on grey'
  64.  
  65.     ansi2[0] = 0x9b;
  66.     ansi2[1] = 0;
  67.     strcat(ansi2, "0;39;39;>0m"); // means `go back to vanilla'
  68.  
  69.     Printf("HowDif 2.02a for Amiga\n\n");
  70.  
  71.     if (argc) /* started from CLI */
  72.     {   if (!(ArgsPtr = ReadArgs
  73.         (   "FILE1/A,FILE2,-V=VANILLA/S,-W=WIDE/S",
  74.             (LONG *) args,
  75.             NULL
  76.         )))
  77.         {   Printf
  78.             (   "Usage: %s <file1> [<file2>] [-v|VANILLA] [-w|WIDE]\n",
  79.                 argv[0]
  80.             );
  81.             cleanexit(EXIT_FAILURE);
  82.         }
  83.         if (args[1])
  84.         {   compare = TRUE;
  85.         }
  86.         if (args[2])
  87.         {   vanilla = TRUE;
  88.         }
  89.         if (args[3])
  90.         {   bpl = 16;
  91.     }   }
  92.     else
  93.     {   // started from Workbench
  94.         Printf
  95.         (   "Usage: %s <file1> [<file2>] [-v|VANILLA] [-w|WIDE]\n",
  96.             argv[0]
  97.         );
  98.         cleanexit(EXIT_FAILURE);
  99.     }
  100.  
  101.     for (i = 0; i <= 1; i++)
  102.     {   if (i == 0 || compare)
  103.         {   if (!(FileHandle = (BPTR) Lock(args[i], ACCESS_READ)))
  104.             {   Printf("Can't lock %s!\n", args[i]);
  105.                 exit(EXIT_FAILURE);
  106.             }
  107.             if (!(FIBPtr = AllocDosObject(DOS_FIB, NULL)))
  108.             {   UnLock(FileHandle);
  109.                 Printf("Can't allocate DOS object!\n");
  110.                 exit(EXIT_FAILURE);
  111.             }
  112.             if (!(Examine(FileHandle, FIBPtr)))
  113.             {   FreeDosObject(DOS_FIB, FIBPtr);
  114.                 UnLock(FileHandle);
  115.                 Printf("Can't examine %s!\n", args[i]);
  116.             }
  117.             size[i] = FIBPtr->fib_Size;
  118.             FreeDosObject(DOS_FIB, FIBPtr);
  119.             FIBPtr = NULL;
  120.             UnLock(FileHandle);
  121.             FileHandle = NULL;
  122.             if (!(MemoryPtr[i] = AllocMem(size[i], NULL)))
  123.             {   Printf("Out of memory!\n");
  124.                 cleanexit(EXIT_FAILURE);
  125.             }
  126.             if (!(FileHandle = (BPTR) Open(args[i], MODE_OLDFILE)))
  127.             {   Printf("Can't open %s for reading!\n", args[i]);
  128.                 cleanexit(EXIT_FAILURE);
  129.             }
  130.             if (Read(FileHandle, MemoryPtr[i], size[i]) != size[i])
  131.             {   Printf("Can't read from %s!\n", args[i]);
  132.                 cleanexit(EXIT_FAILURE);
  133.             }
  134.             Close(FileHandle);
  135.             FileHandle = NULL;
  136.     }   }
  137.  
  138.     if (compare)
  139.     {   if (size[0] <= size[1])
  140.         {   primary   = args[0];
  141.             secondary = args[1];
  142.         } else
  143.         {   primary   = args[1];
  144.             secondary = args[0];
  145.             size[2] = size[0];
  146.             size[0] = size[1];
  147.             size[1] = size[2];
  148.             MemoryPtr[2] = MemoryPtr[0];
  149.             MemoryPtr[0] = MemoryPtr[1];
  150.             MemoryPtr[1] = MemoryPtr[2];
  151.         }
  152.         Printf("  Primary file is %s (%ld bytes).\n",     primary, size[0]);
  153.         Printf("Secondary file is %s (%ld bytes).\n\n", secondary, size[1]);
  154.  
  155.         for (br = 0; br < size[0]; br++) // do this loop as long as the file has not ended
  156.         {   if (MemoryPtr[0][br] != MemoryPtr[1][br]) // compare the two single bytes
  157.             {   bw++;    // add one to the counter showing # of mismatches
  158.     }   }   }
  159.     else
  160.     {   Printf("File is %s (%ld bytes).\n\n", args[0], size[0]);
  161.     }
  162.  
  163.     if (size[0] > 65535)
  164.     {   Printf("  ");
  165.     }
  166.  
  167.     if (bpl == 14)
  168.     {   Printf("       0011 2233 4455 6677 8899 AABB CCDD 0123456789ABCD 0123456789ABCD\n");
  169.         if (size[0] > 65535)
  170.         {   Printf("  ");
  171.         }
  172.         Printf("       ---------------------------------- -------------- --------------\n");
  173.     } else
  174.     {   // assert(bpl == 16);
  175.         Printf("       0011 2233 4455 6677 8899 AABB CCDD EEFF 0123456789ABCDEF\n");
  176.         if (size[0] > 65535)
  177.         {   Printf("  ");
  178.         }
  179.         Printf("       --------------------------------------- ----------------\n");
  180.     }
  181.  
  182.     for (i = 0; i < size[0]; i += bpl)
  183.     {   output[0] = 0;
  184.         deinvert();
  185.         strcat(output, "$");
  186.  
  187.         if (size[0] > 65535)
  188.         {   hexalize(i / 16777216); // do 1st byte
  189.             j = i % 16777216;       // remove 1st byte
  190.             hexalize(j / 65536);    // do 2nd byte
  191.             j %= 65536;             // remove 2nd byte
  192.         } else
  193.         {   j = i;
  194.         }
  195.         hexalize(j / 256);      // do 3rd byte
  196.         hexalize(j % 256);      // do 4th byte
  197.  
  198.         strcat(output, ": ");
  199.         for (j = 0; j < bpl; j++)
  200.         {   if (size[0] > i + j)
  201.             {   if (compare)
  202.                 {   if (MemoryPtr[0][i + j] != MemoryPtr[1][i + j])
  203.                     {   deinvert();
  204.                     } else
  205.                     {   invert();
  206.                 }   }
  207.                 hexalize(MemoryPtr[0][i + j]);
  208.             } else
  209.             {   deinvert();
  210.                 strcat(output, "##");
  211.             }
  212.             if (j % 2)
  213.             {   deinvert();
  214.                 strcat(output, " ");
  215.         }   }
  216.  
  217.         if (bpl < 16)
  218.         {   for (j = 0; j < bpl; j++)
  219.             {   if (size[0] > i + j)
  220.                 {   if (compare)
  221.                     {   if (MemoryPtr[0][i + j] != MemoryPtr[1][i + j])
  222.                         {   deinvert();
  223.                         } else
  224.                         {   invert();
  225.                     }   }
  226.                     if
  227.                     (    MemoryPtr[0][i + j] < ' '
  228.                       || (MemoryPtr[0][i + j] >= 0x80 && MemoryPtr[0][i + j] <= 0x9F)
  229.                     ) // if an unprintable character
  230.                     {   strcat(output, ".");
  231.                     } else
  232.                     {   length = strlen(output);
  233.                         output[length] = MemoryPtr[0][i + j];
  234.                         output[length + 1] = 0;
  235.                 }   }
  236.                 else
  237.                 {   deinvert();
  238.                     strcat(output, "#");
  239.             }   }
  240.  
  241.             deinvert();
  242.             strcat(output, " ");
  243.         }
  244.  
  245.         for (j = 0; j < bpl; j++)
  246.         {   if (size[0] > i + j)
  247.             {   if (compare)
  248.                 {   if (MemoryPtr[0][i + j] != MemoryPtr[1][i + j])
  249.                     {   deinvert();
  250.                     } else
  251.                     {   invert();
  252.                 }   }
  253.                 length = strlen(output);
  254.                 output[length] = arcadia[MemoryPtr[0][i + j] % 64];
  255.                 output[length + 1] = 0;
  256.             } else
  257.             {   deinvert();
  258.                 strcat(output, "#");
  259.         }   }
  260.  
  261.         deinvert();
  262.         Printf("%s\n", output);
  263.  
  264.         /* From RKM Libraries, p. 432:
  265.  
  266.         get current state of signals */
  267.         signals = SetSignal(0L, 0L);
  268.  
  269.         // check for Ctrl-C
  270.         if (signals & SIGBREAKF_CTRL_C)
  271.         {   // then clear the Ctrl-C signal
  272.             SetSignal(0L, SIGBREAKF_CTRL_C);
  273.  
  274.             Printf("User break!\n");
  275.             cleanexit(EXIT_SUCCESS);
  276.     }   }
  277.  
  278.     // when the program is all done comparing, print a summary report onscreen
  279.  
  280.     Printf("\nTotal bytes read: %ld\n", size[0]);
  281.  
  282.     if (compare)
  283.     {   Printf("Mismatches found: %ld\n", bw);
  284.  
  285.         /* calculate percentage:
  286.             percent1 is the percentage magnified 1 million times.
  287.             eg. 1 million = 1%, 100 million = 100%, 56,723,432 = 56.723432%.
  288.             By scaling in this way we preserve precision whilst avoiding
  289.             the need for true floating point mathematics.
  290.             percent2 is the actual integer percentage. */
  291.     
  292.         if (!bw)
  293.         {   percent2 = 0;
  294.         } else
  295.         {   percent1 = (100000000L / size[0]) * bw;
  296.             percent2 = percent1 / 1000000L;
  297.         }
  298.         Printf("Difference:       %ld%%\n", percent2);
  299.     }
  300.  
  301.     cleanexit(EXIT_SUCCESS); // end of the program. go back to DOS
  302. }
  303.  
  304. MODULE void invert(void)
  305. {   if (!inverted)
  306.     {   if (!vanilla)
  307.         {   strcat(output, ansi1);
  308.         }
  309.         inverted = TRUE;
  310. }   }
  311. MODULE void deinvert(void)
  312. {   if (inverted)
  313.     {   if (!vanilla)
  314.         {   strcat(output, ansi2);
  315.         }
  316.         inverted = FALSE;
  317. }   }
  318.  
  319. MODULE void cleanexit(SLONG rc)
  320. {   if (FIBPtr)
  321.     {   FreeDosObject(DOS_FIB, FIBPtr);
  322.     }
  323.     if (FileHandle)
  324.     {   Close(FileHandle);
  325.     }
  326.     if (MemoryPtr[0])
  327.     {   FreeMem(MemoryPtr[0], size[0]);
  328.     }
  329.     if (MemoryPtr[1])
  330.     {   FreeMem(MemoryPtr[1], size[1]);
  331.     }
  332.     if (ArgsPtr)
  333.     {   FreeArgs(ArgsPtr);
  334.     }
  335.     exit(EXIT_SUCCESS);
  336. }
  337.  
  338. MODULE void hexalize(UBYTE data)
  339. {   TEXT tempstring[3];
  340.  
  341.     // Converts an unsigned byte into a hexadecimal string
  342.  
  343.     // do the high byte
  344.     if (data / 16 >= 10)
  345.     {   tempstring[0] = (data / 16) - 10 + 'A'; // must be done in this order to prevent overflow during calculation of the value
  346.     } else
  347.     {   tempstring[0] = (data / 16) + '0';
  348.     }
  349.  
  350.     // now the low byte
  351.     if (data % 16 >= 10)
  352.     {   tempstring[1] = (data % 16) - 10 + 'A';
  353.     } else
  354.     {   tempstring[1] = (data % 16) + '0';
  355.     }
  356.     tempstring[2] = 0;
  357.     strcat(output, tempstring);
  358. }
  359.